﻿#include "tunnelcallback.h"
#include "udptunnel.h"

#include <net/udpchannel.h>
#include "QsLog.h"

QNET_USING_NAMESPACE
UdpTunnel::UdpTunnel(const IPFiveTuple &ipTuple)
    :m_ipTuple(ipTuple)
{
    m_innerThread = Q_NULLPTR;
    m_chn = Q_NULLPTR;
    m_state = false;
}

UdpTunnel::~UdpTunnel()
{

}

bool UdpTunnel::build()
{
    if(m_chn)
    {
        m_chn->deleteLater();
    }
    m_chn = new UdpChannel;

    bool bind = m_chn->bind(m_ipTuple.localAddr(), m_ipTuple.localPort());
    if(bind)
    {
        m_chn->setRemote(m_ipTuple.remoteAddr(), m_ipTuple.remotePort());
        m_chn->setReading(this);
        m_state = true;
        onStateChanged(m_state);

        m_innerThread = new QThread;
        m_innerThread->start();

        QObject::connect(m_innerThread, &QThread::finished, m_innerThread, &QThread::deleteLater);
        QObject::connect(m_innerThread, &QThread::finished, m_chn, &UdpChannel::deleteLater);
        m_chn->moveToThread(m_innerThread);

    }else
    {
        m_chn->deleteLater();
        m_chn = Q_NULLPTR;
    }
    return bind;
}

void UdpTunnel::destory()
{
    if(m_chn)
    {
        m_chn->close();
        m_chn->setReading(Q_NULLPTR);
        m_chn = Q_NULLPTR;
    }
    if(m_innerThread)
    {
        m_innerThread->exit();
    }
}

int UdpTunnel::write(QByteArray &src)
{
    return m_chn->write(src);
}

bool UdpTunnel::state()
{
    return m_state;
}

void UdpTunnel::disConnect()
{
    m_state = false;
    onStateChanged(m_state);
}

void UdpTunnel::fetchTuple(IPFiveTuple &tuple)
{
    tuple.setType(IPFiveTuple::Type_Udp);
    if(m_chn)
    {
        tuple.setLocalPort(m_chn->localPort());
        tuple.setLocalAddr(m_chn->localAddress());
        tuple.setRemotePort(m_chn->remotePort());
        tuple.setRemoteAddr(m_chn->remoteAddress());
    }
}

void UdpTunnel::onProc(const QByteArray &arry)
{
    auto func = [=](TunnelCallback *item)->void {item->onProc(arry);};
    execEach(func);
}

void UdpTunnel::onStateChanged(bool connected)
{
    auto func = [=](TunnelCallback *item)->void {item->onStateChange(connected);};
    execEach(func);
}
